#include <UnitTest++.h>
#include <Utility/RecordFile.hpp>
#include <Math/Vector3.hpp>
#include <Math/Vector2.hpp>
#include <Math/Array1.hpp>
using namespace zzz;

SUITE(RecordFileTest) 
{
  TEST(WriteAndRead)
  {
    int x=123;
    float y=456;
    Vector3d z(1,2,3);
    vector<Vector2i> w;
    w.push_back(Vector2i(2,3));
    w.push_back(Vector2i(22,33));
    const zint32 RF_X=1;
    const zint32 RF_Y=2;
    const zint32 RF_Z=3;
    const zint32 RF_W=4;
    const zint32 RF_MYDATA=5;
    const zint32 RF_MYDATA_POS=1;
    const zint32 RF_MYDATA_COLOR=2;
    const zint32 RF_ARR=6;
    struct MyData {
      Vector3f pos_;
      Vector3uc color_;
    }my_data;
    my_data.pos_=Vector3f(1,2,3);
    my_data.color_=Vector3uc(128,255,0);
    Array<1,double> arr(10);
    for (zuint i=0; i<10; i++)
      arr[i]=i*2;

    RecordFile rf;
    rf.SaveFileBegin("recordtest.rf");
    IOObject<int>::WriteFileR(rf, RF_X, x);
    IOObject<float>::WriteFileR(rf, RF_Y, y);
    IOObject<Vector3d>::WriteFileR(rf, RF_Z, z);
    IOObject<vector<Vector2i>>::WriteFileR(rf, RF_W, w);
    rf.WriteChildBegin(RF_MYDATA);
    IOObject<Vector3f>::WriteFileR(rf, RF_MYDATA_POS, my_data.pos_);
    IOObject<Vector3uc>::WriteFileR(rf, RF_MYDATA_COLOR, my_data.color_);
    rf.WriteChildEnd();
    IOObject<Array<1,double> >::WriteFileR(rf, RF_ARR, arr);
    rf.SaveFileEnd();

    rf.LoadFileBegin("recordtest.rf");
    int rx;
    float ry;
    Vector3d rz;
    vector<Vector2i> rw;
    MyData rmy_data;
    Array<1,double> rarr;
    IOObject<vector<Vector2i>>::ReadFileR(rf, RF_W, rw);
    IOObject<int>::ReadFileR(rf, RF_X, rx);
    IOObject<Vector3d>::ReadFileR(rf, RF_Z, rz);
    IOObject<float>::ReadFileR(rf, RF_Y, ry);
    rf.ReadChildBegin(RF_MYDATA);
    IOObject<Vector3f>::ReadFileR(rf, RF_MYDATA_POS, rmy_data.pos_);
    IOObject<Vector3uc>::ReadFileR(rf, RF_MYDATA_COLOR, rmy_data.color_);
    rf.ReadChildEnd();
    IOObject<Array<1,double> >::ReadFileR(rf, RF_ARR, rarr);
    int tmp;
    IOObject<int>::ReadFileR(rf, 99999, tmp);
    rf.LoadFileEnd();

    CHECK_EQUAL(x,rx);
    CHECK_EQUAL(y,ry);
    CHECK_EQUAL(z,rz);
    CHECK_EQUAL(w.size(), rw.size());
    for (zuint i=0; i<w.size(); i++)
      CHECK_EQUAL(w[i], rw[i]);
    CHECK_EQUAL(my_data.pos_, rmy_data.pos_);
    CHECK_EQUAL(my_data.color_, rmy_data.color_);
    for (zuint i=0; i<w.size(); i++)
      CHECK_EQUAL(w[i], rw[i]);
  }

  TEST(RepeatReadAndWrite)
  {
    struct MyData{
      int x;
      float y;
    };
    vector<MyData> data;
    const zint32 RF_DATA=1;
    const zint32 RF_DATA_SIZE=1;
    const zint32 RF_DATA_MYDATA=2;
    const zint32 RF_DATA_MYDATA_X=1;
    const zint32 RF_DATA_MYDATA_Y=2;
    const zint32 RF_ANOTHER=2;
    double another = C_PI;

    for (zuint i=0; i<10; i++) {
      data.push_back(MyData());
      data.back().x=i;
      data.back().y=i*2.5f;
    }
    
    RecordFile rf;
    rf.SaveFileBegin("recordtest2.rf");
    rf.WriteChildBegin(RF_DATA);
      IOObject<zuint>::WriteFileR(rf, RF_DATA_SIZE, data.size());
      rf.WriteRepeatBegin(RF_DATA_MYDATA);
        for (zuint i=0; i<data.size(); i++) {
          rf.WriteRepeatChild();
          IOObject<int>::WriteFileR(rf, RF_DATA_MYDATA_X, data[i].x);
          IOObject<float>::WriteFileR(rf, RF_DATA_MYDATA_Y, data[i].y);
        }
      rf.WriteRepeatEnd();
    rf.WriteChildEnd();
    IOObject<double>::WriteFileR(rf, RF_ANOTHER, another);
    rf.SaveFileEnd();

    vector<MyData> rdata;
    double ranother;
    rf.LoadFileBegin("recordtest2.rf");
    IOObject<double>::ReadFileR(rf, RF_ANOTHER, ranother);
    CHECK_EQUAL(another, ranother);
    zuint tmp;
    rf.ReadChildBegin(RF_DATA);
      IOObject<zuint>::ReadFileR(rf, RF_DATA_SIZE, tmp);
      CHECK_EQUAL(data.size(), tmp);
      rf.ReadRepeatBegin(RF_DATA_MYDATA);
        while(rf.ReadRepeatChild()) {
          int x;
          float y;
          IOObject<int>::ReadFileR(rf, RF_DATA_MYDATA_X, x);
          IOObject<float>::ReadFileR(rf, RF_DATA_MYDATA_Y, y);
          rdata.push_back(MyData());
          rdata.back().x = x;
          rdata.back().y = y;
          CHECK_EQUAL(data[rdata.size()-1].x, rdata.back().x);
          CHECK_EQUAL(data[rdata.size()-1].y, rdata.back().y);
        }
      rf.ReadRepeatEnd();
      CHECK_EQUAL(data.size(), rdata.size());
    rf.ReadChildEnd();
    rf.LoadFileEnd();
  }
}